<?php

class EntityService extends AbstractService
{
    /**
     * @var GameService
     */
    private static $instance;

    /**
     * @var array $defaultEntityLength
     */
    private $defaultEntityLength = array(
        13, // default entityId length
        3,  // default action length
        2,  // default module length
        8   // default subId length
    );

    /**
     * @var array $defaultItemIdLength
     */
    private $defaultItemIdLength = array(
        8, // default item id length
        4, // default item type length
        4, // default item sub id length
    );

    /**
     * Get the instance of GameService.
     *
     * @return EntityService
     */
    public static function get()
    {
        if (!self::$instance) {
            self::$instance = new EntityService();
        }
        return self::$instance;
    }

    /**
     * Construction.
     */
    protected function __construct()
    {
        parent::__construct();

        // determine entity length config
        try {
            $actionLength = $this->readGlobalConfig('actionLength');
            $moduleLength = $this->readGlobalConfig('moduleLength');
            $subIdLength = $this->readGlobalConfig('subIdLength');

            // update default entity length
            $this->defaultEntityLength = array(
                $actionLength + $moduleLength + $subIdLength,
                $actionLength,
                $moduleLength,
                $subIdLength
            );
        } catch (Exception $e) {
            // do nothing
        }
    }

    /**
     * 处理创建时的逻辑
     *
     * @param int $shardId
     * @return void
     */
    public function handleCreate($shardId)
    {

    }

    /**
     * 处理登录时的逻辑
     *
     * @param int $userId
     * @return void
     */
    public function handleLogin($userId)
    {
    }

    /**
     * 提供Service层的所有数据
     *
     * @param int $shardId
     * @return mixed
     */
    public function info($shardId)
    {
        return false;
    }

    /**
     * Read mission global config value.
     *
     * <pre>
     * $globalConfigs => array(
     *     $key => array(
     *         'key' => $key,
     *         'value' => $value,
     *     ),
     *     ...
     * )
     * </pre>
     *
     * @param string $key
     * @return mixed
     */
    private function readGlobalConfig($key)
    {
        $config = SzConfig::get()->loadAppConfig(GameConst::CONFIG_ENTITY, $key, true);

        return $config['value'];
    }

    /**
     * Parse the entity id into three parts.
     *
     * @param string $entityId
     * @return array
     * <pre>
     * array($action, $module, $subId)
     * </pre>
     */
    public function parseEntityId($entityId)
    {
        list($entityLength, $actionLength, $moduleLength, $subIdLength) = $this->defaultEntityLength;

        $entityId   = sprintf("%1$0{$entityLength}d", str_replace('"', '', $entityId)); // fill number length to $entityLength
        $action     = (int)substr($entityId, 0, $actionLength); // remove the leading 0 numbers
        $module     = (int)substr($entityId, $actionLength, $moduleLength);
        $subId      = (int)substr($entityId, $actionLength + $moduleLength, $subIdLength);

        return array($action, $module, $subId);
    }

    /**
     * Build entity id from three parts.
     *
     * @param int $action action id
     * @param int $module functional module id
     * @param int $subId detailed sub id under some module
     * @throws SzException 20021
     * @return int $entityId
     */
    public function buildEntityId($action, $module, $subId)
    {
        list(, , $moduleLength, $subIdLength) = $this->defaultEntityLength;

        // 功能模块id和subId可能不足他的规范字数，所以需要补足
        $module = sprintf("%1$0{$moduleLength}d", $module); // fill number length to $moduleLength
        $subId = sprintf("%1$0{$subIdLength}d", $subId);  // fill number length to $subIdLength
        $entityId = $action . $module . $subId;

        if (empty($entityId) || (!is_numeric($entityId) || is_float($entityId))) {
            throw new SzException(20021);
        }

        return $entityId;
    }

    /**
     * get the item type Id
     *
     * @param $itemId
     * @return array
     * <pre>
     *  array(
     *      $itemType,
     *      $itemSubId
     * )
     * </pre>
     */
    public function parseItemId($itemId)
    {
        list($itemIdLength, $itemTypeLength, $itemSubIdLength) = $this->defaultItemIdLength;

        $itemId     = sprintf("%1$0{$itemIdLength}d", $itemId); // fill number length to $entityLength
        $itemType   = (int)substr($itemId, 0, $itemTypeLength); // remove the leading 0 numbers
        $itemSubId  = (int)substr($itemId, $itemTypeLength, $itemIdLength);

        return array($itemType, $itemSubId);
    }
}